<?php

/**
 * Framework_DB
 *
 * Extends the base Framework_Object class to include a database connection.
 *
 * @author Application Support Group
 * @package BAMF
*/
abstract class Framework_DB extends Framework_Object {

	/**
	 * $db
	 * @var mixed PEAR DB connection
	 */

	protected $db ;
	protected $dsn ;

	public function __construct( $theDsn=FRAMEWORK_DSN ) {

// NOTE: the dsn array for the existing connection does not seem to include
// the database name, although it does exist in the separate property. This
// is causing the connection re-use check to fail, causing massive
// performance problems.

		parent::__construct() ;

		// force autoloading of MDB2
		$apiVersion = MDB2::apiVersion() ;

		$this->dsn = Framework_DB_Utility::unserializeDsn( $theDsn ) ;

		if ( $this->dsn != null ) {
			if( !is_array( $this->dsn )) {
				$this->dsn = MDB2::parseDSN( $this->dsn ) ;
			}

			$connection = null ;

			// Check the connection pool to see if we are already connected to the specified dsn.
	
			if ( isset( $GLOBALS[ 'connections' ] ) && count( $GLOBALS[ 'connections' ] ) > 0 ) {
				foreach( $GLOBALS[ 'connections' ] as $existingConnection ) {
					if( $this->dsnMatches( $existingConnection->getDSN('array'), $this->dsn )) {
						$connection = $existingConnection ;
						break ;
					} 
				}
			} else {
				$GLOBALS[ 'connections' ] = array() ;
			}
	
			// If there is no pre-existing connection to use, then create a new one
			// and add it to the connection pool.
			if ( $connection === null ) {

				$options = array() ;
				if( DB_PERSISTENT_CONNECTION ) { $options['persistent'] = DB_PERSISTENT_CONNECTION ; }
				if( MDB2_DISABLE_PORTABILITY ) { 

					$options['portability'] = MDB2_PORTABILITY_NONE ;

					if( MDB2_ENABLE_DELETE_COUNT ) {
						$options['portability'] |= MDB2_PORTABILITY_DELETE_COUNT;
					}

					if( MDB2_ENABLE_EMPTY_TO_NULL ) {
						$options['portability'] |= MDB2_PORTABILITY_EMPTY_TO_NULL;
					}

					if( MDB2_ENABLE_ERRORS ) {
						$options['portability'] |= MDB2_PORTABILITY_ERRORS;
					}

					if( MDB2_ENABLE_FIX_ASSOC_FIELD_NAMES ) {
						$options['portability'] |= MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES;
					}

					if( MDB2_ENABLE_FIX_CASE ) {
						$options['portability'] |= MDB2_PORTABILITY_FIX_CASE;
					}

					if( MDB2_ENABLE_NUMROWS ) {
						$options['portability'] |= MDB2_PORTABILITY_NUMROWS;
					}

					if( MDB2_ENABLE_RTRIM ) {
						$options['portability'] |= MDB2_PORTABILITY_RTRIM;
					}

				}

				

				$connection = &MDB2::connect( $this->dsn, $options );

				if( !Framework_ErrorHandler::isError( $connection, null, false )) {
					$connection->setFetchMode(MDB2_FETCHMODE_ASSOC);
					$GLOBALS[ 'connections' ][] = $connection ;
				} else {
					if ( SHOW_DEBUG ) {
						self::handleBadConnection( $this->dsn, $connection->getMessage() . ' ('.$connection->getDebugInfo().')') ;
					} else {
						self::handleBadConnection( $this->dsn, $connection->getMessage()) ;
					}
				}
				
			} 
			
			$this->db = $connection ;

		} else {
			if( DIE_ON_NULL_DSN ) {
				self::handleBadConnection( null, "DSN is null" ) ;
			}
		}

	}// end constructor


// The dsn array for existing connections tends to be different from the
// new one even if they are to the same database, so we need to do some
// manual checking. We will only use the minimum number of fields, ignoring
// those that shouldn't be required to identify what we're connecting to.

	protected function dsnMatches( $existingDsn, $newDsn ) {
		$_output = true ;
		
		$keys = array( 'phptype', 'hostspec', 'database', 'username', 'password' ) ;
		
		foreach( $keys as $key ) {
			if ( $existingDsn[ $key ] != $newDsn[ $key ] ) {
				$_output = false ;
				break ;
			}
		}

		
		return $_output ;
	}

	protected static function handleBadConnection( $dsn=null, $msg=null ) {
		if( DIE_ON_NULL_DSN && is_null( $dsn )) {
			Framework_Util_Debug::show( "DSN is undefined and DIE_ON_NULL_DSN is TRUE." ) ;

		} elseif( DIE_ON_BAD_DSN || is_null( BAD_DSN_REDIRECT_URL )) {
			if( empty( $msg )) {
				Framework_Util_Debug::show( "No database connection, or DSN is undefined and DIE_ON_NULL_DSN is TRUE." ) ;
			} else {
				Framework_Util_Debug::show( array( "No database connection.", $msg )) ;
			}

		} else {
			header( "Location: " . BAD_DSN_REDIRECT_URL ) ;
		}

		return ;

	}// end handleBadConnection


	public function __destruct() {
		parent::__destruct();
	}

}// end class

?>
